package config

import (
	"errors"
	"os"
	"path/filepath"
	"sync/atomic"

	"github.com/bytedance/sonic"
	"github.com/imroc/req/v3"
	"github.com/jinzhu/copier"
	"github.com/nats-io/nats.go"
	"github.com/samber/lo"
	"github.com/spf13/viper"
)

type DynamicConf struct {
	config atomic.Value
}

type Conf struct {
	Mode                 string `json:"mode"`                    // develop prod test
	MarketDataSource     string `json:"market_data_source"`      // 数据来源 XueQiu Tencent
	MarketConfigFilePath string `json:"market_config_file_path"` // 数据配置文件路径
	MySql                struct {
		Host     string `json:"host"`
		Port     int    `json:"port"`
		UserName string `json:"username"`
		Password string `json:"password"`
	}

	Redis struct {
		Addr     string `json:"addr"`
		Password string `json:"password"`
		DB       int    `json:"db"`
	}

	Nats struct {
		URL      string `json:"url"`
		User     string `json:"user"`
		Password string `json:"password"`
	}

	EnableNotificationBark bool `json:"enable_notification_bark"` // 是否启用Bark通知
	EnableReqDebug         bool `json:"enable_req_debug"`         // 是否启用请求调试
	EnableNewsPush         bool `json:"enable_news_push"`         // 是否启用新闻推送
	NewsSource             int  `json:"news_source"`              // 新闻来源 全部=0, 雪球=1, 财联社=2

	XueQiu struct {
		Token string `json:"token"` // 雪球token
	}

	Log struct {
		Level      string `json:"level"`       // 日志级别
		Filename   string `json:"filename"`    // 日志文件名
		MaxSize    int    `json:"max_size"`    // 日志文件最大大小
		MaxBackups int    `json:"max_backups"` // 日志文件最大备份数
		MaxAge     int    `json:"max_age"`     // 日志文件最长保留时间
		Compress   bool   `json:"compress"`    // 是否压缩日志
	}

	ClickHouse struct {
		Addr     []string `json:"addr"`
		Database string   `json:"database"`
		Username string   `json:"username"`
		Password string   `json:"password"`
	}

	Symbols []string `json:"symbols"` // 股票列表
	CCI     []string `json:"cci"`     // CCI指标
	MACD    []string `json:"macd"`    // MACD指标
	MA      struct {
		Periods []string `json:"periods"` // MA周期
		Ema     []int    `json:"ema"`     // 均线
	}

	Realtime struct {
		UpVelocity   float64 `json:"up_velocity"`   // 涨速
		DownVelocity float64 `json:"down_velocity"` // 跌速
	}

	Kline []string `json:"kline"` // K线周期
}

func New() *DynamicConf {
	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AddConfigPath("./")
	viper.AddConfigPath("./configs") // 基于程序当前目录
	err := viper.ReadInConfig()
	if err != nil {
		var cfgErr viper.ConfigFileNotFoundError
		if !errors.As(err, &cfgErr) {
			panic(err)
		}

		wd, _ := os.Getwd()
		currentDir := wd
		var previousDir string

		for {
			// 添加当前目录到配置路径
			viper.AddConfigPath(filepath.Join(currentDir, "configs"))

			// 获取父目录
			previousDir = currentDir
			currentDir = filepath.Dir(currentDir)

			// 检查是否到达根目录（跨平台兼容）
			if currentDir == previousDir {
				break // 到达根目录
			}
		}

		err = viper.ReadInConfig()
		if err != nil {
			panic(err)
		}
	}

	var conf Conf
	err = viper.Unmarshal(&conf)
	if err != nil {
		panic(err)
	}

	// 去重,合并
	kline := append(conf.CCI, conf.MA.Periods...)
	conf.Kline = lo.Uniq(kline)

	var dc DynamicConf
	dc.config.Store(&conf)

	return &dc
}

func (d *DynamicConf) Get() *Conf {
	return d.config.Load().(*Conf)
}

// Watch 采用nats配置更新
func (d *DynamicConf) Watch(ns *nats.Conn) {
	_, _ = ns.Subscribe("config.update", func(msg *nats.Msg) {
		var keys []string
		_ = sonic.Unmarshal(msg.Data, &keys)

		// 深度copy
		oldConf := d.Get()
		var newConf Conf
		_ = copier.CopyWithOption(&newConf, oldConf, copier.Option{IgnoreEmpty: true, DeepCopy: true})

		for _, key := range keys {
			switch key {
			case "enable_req_debug":
				newConf.EnableReqDebug = !newConf.EnableReqDebug
				if oldConf.EnableReqDebug {
					req.DisableDumpAll().DisableDebugLog().DisableTraceAll()
					continue
				}
				req.DevMode()
			}
		}

		d.config.Store(&newConf)
	})
}
